/*
 * 文件名称：MsgClient.h
 * 文件描述：消息客户端主逻辑，用于与消息服务器之间传递消息
 * 作者信息：Satan-Emperor
 * 版本信息：V1.0.0
 * 修改历史：2014-04-22
 */

#ifndef _MSGCLIENT_H_
#define _MSGCLIENT_H_

#include "MsgQueue.h"
#include "AppThread.h"

#include <map>
#include <semaphore.h>

/* 消息反馈掩码 */
#define REPLY_MESSAGE_MASK		0x40000000

/* 最大的消息大小20kb */
#define MAX_MESSAGE_BUFF_SIZE	20*1024

/* 消息头结构体 */
typedef struct tagMsgHead
{
    unsigned int msgId;		/* 消息ID */
    int reply;				/* 是否需要反馈 */
    int clientFd;			/* 客户端的文件描述符 */
    int dataLen;			/* 数据的长度 */
    int privData;			/* 私有数据 */
    char jSonpFun[20];		/* jSon函数指针 */
    char data[0];			/* 数组名，不占空间，紧接结构体地址，用于数据扩展 */
} __attribute__((packed)) MsgHead, *PMsgHead;	/* 取消GCC的结构体优化 */

/* 消息回调函数指针 */
typedef void (*MsgHandle)(const char * , int);

/* 消息映射结构体 */
typedef struct tagMsgMap
{
    int msgId;				/* 消息ID */
    MsgHandle handle;		/* 消息回调函数指针 */
} MsgMap;

/* 消息客户端类 */
class CMsgClient
{
public:
    CMsgClient(const char *msgServerIp, int port, int interval);
    virtual ~CMsgClient();

public:
    void waitMsg();		/* 接受消息 */
    int registerMsgHandle(int msgId, MsgHandle handle);	/* 注册消息回调 */
    int unRegisterMsgHandle(int msgId);					/* 注销消息回调 */
    int sendMsg(int msgId, char reply, const char *pData, int dataLen, int clientFd = 0, int privData = 0, char *jSonpFun = NULL);
    int replyMsg(PMsgHead pMsgHead, const char *pData, int dataLen);
    int clearMsgQueue(void);

protected:
    int init(void);
    int onRecieveMsg();
    void onDisconnect();
    int sendDataToServer(const char *pData, int dataLen);
    int msgHandle(const char *pRecvBuf, int bufLen);
    int consumeMsg(void);
    int msgCheck(const char *pRecvBuf, int bufLen);

    static void *msgSendThreadHandle(void *param);

private:
    char mMsgServerIp[32];
    int mMsgServerPort;
    int mInterval;
    int mSocket;
    int mEpoll;
    std::map<int, MsgHandle> mMsgMapTbl;
    MsgQueue mMsgQueue;
    AppThread mMsgSendThread;
    char mRecieveBuff[MAX_MESSAGE_BUFF_SIZE];
    int mRecievedLen;
    bool isThreadStopped;
    bool isThreadRun;
    int msgTimeOutCnt;
    time_t lastDetectTime;
};

#endif /* _MSGCLIENT_H_ */
